﻿using System;
using JinianNet.Common;
using System.IO;
using System.Text;
using JinianNet.Caching;

namespace JinianNet.Web
{
    public partial class Cache
    {
        public class FileCache : ICache
        {
            //[Data="",Type="String"]
            #region ICache 成员

            const string CachePrefix = "__page__";
            const string CacheSuffix = ".config";
            public static int Expires = 30;

            private string GetPath(string path)
            {
                if (string.IsNullOrEmpty(path))
                    throw new ArgumentException("path");
                return Common.Path.Concat(Path, string.Concat(path.Replace("/", "_").Replace("\\", "_").Replace(":", "_").Replace("*", "_").Replace("?", "_").Replace("\"", "_").Replace("<", "_").Replace(">", "_").Replace("|", "_"), CacheSuffix));
            }

            public string Path
            {
                get
                {
                    return Common.Path.Concat(HttpRunInfo.SitePath, "Cache");
                }

            }

            public int Count
            {
                get { return Directory.GetFiles(Path, CacheSuffix).Length; }
            }

            public object this[string key]
            {
                get
                {
                    return Get(key);
                }
                set
                {
                    Insert(key, value);
                    //if(File.Exists(System.IO.Path.Combine("")))
                }
            }

            public object Get(string key)
            {
                string path = GetPath(key);
                FileInfo fc = new FileInfo(path);
                if (fc.Exists)
                {
                    string[] result = File.ReadAllLines(path);
                    if (result.Length >= 3 && fc.LastWriteTime.AddMinutes(int.Parse(result[0])) >= DateTime.Now)
                    {
                        string[] value = new string[result.Length - 2];
                        string returnValue;
                        if (result.Length == 1)
                        {
                            returnValue = result[2];
                        }
                        else
                        {
                            Array.Copy(result, 2, value, 0, value.Length);
                            returnValue = string.Concat(value);
                        }
                        switch (result[1])
                        {
                            case "System.String":
                                return returnValue;
                            case "System.Boolean":
                            case "System.DateTime":
                            case "System.Decimal":
                            case "System.Double":
                            case "System.Int16":
                            case "System.Int32":
                            case "System.Int64":
                            case "System.Single":
                            case "System.UInt16":
                            case "System.UInt32":
                            case "System.UInt64":
                                return Convert.ChangeType(result[1], Type.GetType(result[1]));
                            case "System.SByte":
                            case "System.Guid":
                            case "System.Byte":
                            case "System.Object":
                            default:
                                return Convert.ChangeType(Convert.ToBase64String(JinianNet.Common.Utils.Serialize(returnValue)), Type.GetType(result[1]));
                        }
                    }
                    File.Delete(path);
                }
                return null;
            }

            public void Insert(string key, object value)
            {
                Insert(key, value, Expires);
            }
            public void Insert(string key, object value, int expires)
            {
                string path = GetPath(key);
                FileInfo fc = new FileInfo(path);
                if (!fc.Directory.Exists)
                {
                    fc.Directory.Create();
                }

                using (System.IO.StreamWriter sw = new System.IO.StreamWriter(path, false))
                {
                    try
                    {
                        string name = value.GetType().FullName;
                        sw.WriteLine(expires.ToString());
                        sw.WriteLine(name);
                        switch (name)
                        {
                            case "System.String":
                            case "System.Boolean":
                            case "System.DateTime":
                            case "System.Decimal":
                            case "System.Double":
                            case "System.Int16":
                            case "System.Int32":
                            case "System.Int64":
                            case "System.Single":
                            case "System.UInt16":
                            case "System.UInt32":
                            case "System.UInt64":
                                sw.WriteLine(value.ToString());
                                break;
                            case "System.SByte":
                            case "System.Guid":
                            case "System.Byte":
                            case "System.Object":
                            default:
                                sw.WriteLine(Convert.ToBase64String(JinianNet.Common.Utils.Serialize(value)));
                                break;
                        }
                    }
                    catch
                    {
                        throw;
                    }
                    finally
                    {
                        sw.Close();
                        sw.Dispose();
                    }
                }
            }

            public void Remove(string key)
            {
                string path = GetPath(key);
                System.IO.File.Delete(path);
            }

            public void RemoveAll()
            {
                string[] files = Directory.GetFiles(Path, CacheSuffix);
                foreach (string value in files)
                    System.IO.File.Delete(value);
            }

            #endregion
        }
    }
}
